package com.ruoyi.app.controller;

import com.ruoyi.app.domain.LogManagement;
import com.ruoyi.common.annotation.Anonymous;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.config.PasswordConfig;
import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.JSONObjectPro;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.domain.tree.TreeHelper;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.enums.YesNoEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.sms.SMSUtil;
import com.ruoyi.framework.web.service.SysLoginService;
import com.ruoyi.system.domain.Feedback;
import com.ruoyi.system.domain.tree.MenuTree;
import com.ruoyi.system.service.IFeedbackService;
import com.ruoyi.system.service.ISysConfigService;
import com.ruoyi.system.service.ISysMenuService;
import com.ruoyi.system.service.ISysUserService;
import com.ruoyi.system.utils.AESUtils;
import com.ruoyi.system.utils.ComLbsUtils;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 描述 APP登录接口
 * 作者 ZhangPing
 * 创建时间 2023/9/27 11:14
 */
@Slf4j
@RestController
@RequestMapping("/app")
public class AppController extends BaseController {

    @Autowired
    private SysLoginService loginService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private SMSUtil smsUtil;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private PasswordConfig passwordConfig;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private IFeedbackService feedbackService;
    @Autowired
    private ISysMenuService menuService;

    @Anonymous
    @ApiOperation(("登录"))
    @PostMapping("/login")
    public AjaxResult login(@RequestParam String username, @RequestParam String password) {
        password = AESUtils.decrypt(password, passwordConfig.getSecretKey().getBytes(StandardCharsets.UTF_8));
        String token = loginService.login(username, password, "", "", Constants.LOGIN_TYPE_APP);
        SysUser user = userService.selectUserByUserName(username);
        JSONObjectPro resBody = new JSONObjectPro()
                .put("token", token)
                .put("name", user.getNickName())
                .put("username", user.getUserName())
                .put("companyName", user.getDept().getDeptName())
                .put("photo", user.getAvatar());
        //暂时兼容老APP，能进去升级APP，code设置为0
        return success(resBody).put(AjaxResult.CODE_TAG, 0);
    }

    @ApiOperation("验证用户名是否重复")
    @PostMapping("/existMobileAndUsername")
    public AjaxResult existMobileAndUsername(@RequestParam String mobile, @RequestParam String username) {
        userService.checkExistUserName(username);
        userService.checkExistMobile(mobile);
        return success();
    }

    @ApiOperation("短信验证码下发")
    @Log(title = "短信验证码下发", businessType = BusinessType.INSERT)
    @PostMapping("/sendSMSCode")
    public AjaxResult sendSMSCode(String mobile) {
        String code = smsUtil.getCode();
        boolean sendResult = smsUtil.sendSMS(mobile, code);
        if (!sendResult) throw new ServiceException("短信验证码发送失败");
        //同一手机号只允许一个验证码有效，删除之前发送到的验证码
        redisCache.deleteObject("SmsCode:" + mobile);
        //将验证码存入redis，时效三分钟
        redisCache.setCacheObject("SmsCode:" + mobile, code, 3, TimeUnit.MINUTES);
        return success();
    }

    @ApiOperation("修改密码")
    @Log(title = "修改密码", businessType = BusinessType.UPDATE)
    @PostMapping("/modifyPassword")
    public AjaxResult modifyPassword(@RequestParam String oldPassword, @RequestParam String newPassword) {
        SysUser user = userService.selectUserById(getUserId());
        oldPassword = AESUtils.decrypt(oldPassword, passwordConfig.getSecretKey().getBytes(StandardCharsets.UTF_8));
        newPassword = AESUtils.decrypt(newPassword, passwordConfig.getSecretKey().getBytes(StandardCharsets.UTF_8));
        if (!SecurityUtils.matchesPassword(oldPassword, user.getPassword())) {
            throw new ServiceException("原密码错误!");
        }
        if (!ComLbsUtils.passwordCheck(newPassword)){
            throw new ServiceException("新密码要求长度8位以上、包含大小写字母、数字和特殊符号");
        }
        user.setPassword(SecurityUtils.encryptPassword(newPassword));
        userService.updateById(user);
        return success();
    }

    @ApiOperation("获取客服电话")
    @PostMapping("/getServicePhone")
    public AjaxResult getServicePhone() {
        String phone = configService.selectConfigByKey("service_phone");
        return success(new JSONObjectPro().put("phone", phone));
    }

    @ApiOperation("意见反馈图片上传")
    @PostMapping("/uploadFeedback")
    public AjaxResult uploadFeedback(@RequestBody MultipartFile[] file) {
        return success(uploadFile(file, "feedback"));
    }

    @ApiOperation("意见反馈保存")
    @Log(title = "意见反馈", businessType = BusinessType.INSERT)
    @PostMapping("/saveFeedback")
    public AjaxResult saveFeedback(@Validated @RequestBody Feedback feedback) {
        feedback.setUserId(getUserId()).setIsDel(String.valueOf(YesNoEnum.NO.getCode()));
        return toAjax(feedbackService.save(feedback));
    }

    /**
     * 操作日志新增
     */
    @ApiOperation("操作日志新增")
    @PostMapping("/operationLogSave")
    public AjaxResult operationLogSave(@RequestBody LogManagement logManagement) {
        return success();
    }

    /**
     * 获取权限菜单树
     *
     * @return 权限菜单树
     */
    @ApiOperation(("获取权限菜单树"))
    @GetMapping("/getPermissions")
    public AjaxResult getPermissions() {
        SysMenu sysMenu = new SysMenu();
        sysMenu.setStatus("0");
        List<SysMenu> sysMenus = menuService.selectMenuList(sysMenu, getUserId());
        List<MenuTree> tree = sysMenus.stream().filter(menu -> menu.getPerms().contains("app:")).map(menu -> new MenuTree()
                .setId(menu.getMenuId().toString())
                .setParentId(menu.getParentId().toString())
                .setLabel(menu.getMenuName())
                .toExtentTree(MenuTree.class)
                .setPerms(menu.getPerms())
                .setMenuType(menu.getMenuType())).collect(Collectors.toList());
        return success(TreeHelper.buildTreeHasParent(tree));
    }

    /**
     * 根据参数键名查询参数值
     */
    @ApiOperation("根据参数键名查询参数值")
    @GetMapping(value = "/configKey/{configKey}")
    public AjaxResult getConfigKey(@PathVariable String configKey)
    {
        return success((Object) configService.selectConfigByKey(configKey));
    }

    /************* 兼容老版本APP升级 ***************/

    @Anonymous
    @ApiOperation("最新版本号")
    @PostMapping("/getVersion")
    public AjaxResult getVersion() {
        File file = new File(RuoYiConfig.getProfile() + "/app");
        File[] files = file.listFiles();
        if (files == null || files.length == 0) return AjaxResult.success().put(AjaxResult.CODE_TAG, 0);
        long lastFileModifiedTime = 0;
        for (File item : files) {
            if (item.lastModified() > lastFileModifiedTime){
                file = item;
                lastFileModifiedTime = item.lastModified();
            }
        }
        return AjaxResult.success("操作成功", file.getName()).put(AjaxResult.CODE_TAG, 0);
    }

    @Anonymous
    @ApiOperation("下载apk")
    @PostMapping("/getApk")
    public void getApk(HttpServletResponse response) {
        File file = new File(RuoYiConfig.getProfile() + "/app");
        File[] files = file.listFiles();
        long lastFileModifiedTime = 0;
        for (File item : files) {
            if (item.lastModified() > lastFileModifiedTime){
                file = item;
                lastFileModifiedTime = item.lastModified();
            }
        }
        if (!file.exists()) return;
        //以流的形式下载文件。
        try {
            InputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            // 设置response的Header
            response.addHeader("Content-Disposition", "attachment;filename=" + file.getName());
            response.addHeader("Content-Length", "" + file.length());
            response.addHeader("Content-Type", "application/vnd.android.package-archive apk");
            OutputStream toClient = new BufferedOutputStream(response.getOutputStream());
            response.setContentType("application/octet-stream");
            toClient.write(buffer);
            toClient.flush();
            toClient.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
